<template>
  <a-modal
    class="image-cropper"
    v-model:open="visible"
    title="裁剪图片"
    :width="changeModalSize(picture?.picWidth)"
    :footer="false"
    @cancel="closeModal"
  >
    <vue-cropper
      ref="cropperRef"
      :img="imageUrl"
      :autoCrop="true"
      :autoCropWidth="picture?.picWidth"
      :autoCropHeight="picture?.picHeight"
      :fixedBox="false"
      :centerBox="true"
      :canMoveBox="true"
      :canMove="false"
      :original="true"
      :info="true"
      :outputType="getOriginImageType"
    />
    <div style="margin-bottom: 13px" />
    <!-- 图片协同编辑操作 -->
    <div class="image-edit-actions" v-if="isTeamSpace">
      <a-space>
        <a-button v-if="editingUser?.id" disabled
          >成员 {{ editingUser?.userName }} 正在编辑。。。
        </a-button>
        <a-button v-if="canEnterEdit" type="primary" @click="enterEdit">进入编辑</a-button>
        <a-button v-if="canExitEdit" @click="exitEdit">退出编辑</a-button>
      </a-space>
    </div>
    <div style="margin-bottom: 13px" />
    <!-- 图片裁剪操作 -->
    <div class="image-cropper-actions">
      <a-space>
        <a-button @click="rotateLeft" :disabled="!canEdit">逆时针旋转</a-button>
        <a-button @click="rotateRight" :disabled="!canEdit">顺时针旋转</a-button>
        <a-button @click="changeScale(1)" :disabled="!canEdit">放大</a-button>
        <a-button @click="changeScale(-1)" :disabled="!canEdit">缩小</a-button>
        <a-button type="primary" :loading="loading" @click="handleConfirm" :disabled="!canEdit">
          确认
        </a-button>
      </a-space>
    </div>
  </a-modal>
</template>

<script setup lang="ts">
import { computed, onUnmounted, ref, watchEffect } from 'vue'
import { uploadPictureByFileUsingPost } from '@/api/pictureController.ts'
import { message } from 'ant-design-vue'
import { useLoginUserStore } from '@/stores/useLoginUserStores.ts'
import PictureEditWebSocket from '@/utils/pictureEditWebSocket.ts'
import { PICTURE_EDIT_ACTION_ENUM, PICTURE_EDIT_MESSAGE_TYPE_ENUM } from '@/constants/picture.ts'
import { SPACE_TYPE_ENUM } from '@/constants/space.ts'
import { changeModalSize } from '@/utils/index.ts'

const loginUserStore = useLoginUserStore()
const loginUser = loginUserStore.loginUser

interface Props {
  imageUrl?: string
  picture?: API.PictureVO
  // 图片上传成功后 通过这个函数传递新的图片返回展示
  spaceId?: number
  space?: API.SpaceVO
  onSuccess?: (newPicture: API.PictureVO) => void
}

const props = defineProps<Props>()

// 是否为团队空间
const isTeamSpace = computed(() => {
  return props.space?.spaceType === SPACE_TYPE_ENUM.TEAM
})

// 编辑器组件的引用
const cropperRef = ref()

// 逆时针旋转
const rotateLeft = () => {
  cropperRef.value.rotateLeft()
  editAction(PICTURE_EDIT_ACTION_ENUM.ROTATE_LEFT)
}

// 顺时针旋转
const rotateRight = () => {
  cropperRef.value.rotateRight()
  editAction(PICTURE_EDIT_ACTION_ENUM.ROTATE_RIGHT)
}

// 缩放
const changeScale = (num: number) => {
  cropperRef.value.changeScale(num)
  if (num > 0) {
    editAction(PICTURE_EDIT_ACTION_ENUM.ZOOM_IN)
  }
  if (num < 0) {
    editAction(PICTURE_EDIT_ACTION_ENUM.ZOOM_OUT)
  }
}

// 确认裁切
const handleConfirm = () => {
  const expectedType = getOriginImageType()
  cropperRef.value.getCropBlob(async (blob: Blob) => {
    const img = new Image()
    img.src = URL.createObjectURL(blob)
    await new Promise((resolve) => {
      img.onload = () => {
        console.log(cropperRef.value)
        const canvas = document.createElement('canvas')
        const ctx = canvas.getContext('2d')
        if (ctx) {
          canvas.width = img.width
          canvas.height = img.height
          ctx.drawImage(img, 0, 0)
          let mimeType
          if (expectedType === 'jpeg') {
            mimeType = 'image/jpeg'
          } else if (expectedType === 'png') {
            mimeType = 'image/png'
          } else if (expectedType === 'webp') {
            mimeType = 'image/webp'
          } else if (expectedType === 'bmp') {
            mimeType = 'image/bmp'
          } else {
            mimeType = 'image/png'
          }
          canvas.toBlob((newBlob) => {
            if (newBlob) {
              // @ts-ignore
              const fileName = (props.picture?.name || 'image') + '.' + expectedType
              const file = new File([newBlob], fileName, { type: newBlob.type })
              handleUpload({ file })
            }
            resolve(null)
          }, mimeType)
        }
      }
    })
  })
}

const getOriginImageType = () => {
  const url = props.picture?.originUrl
  // 若没有图片 URL，默认返回 'png'
  if (!url) {
    return 'png'
  }
  const lastDotIndex = url.lastIndexOf('.')
  // 若 URL 中没有点号，默认返回 'png'
  if (lastDotIndex === -1) {
    return 'png'
  }
  const ext = url.slice(lastDotIndex + 1).toLowerCase()
  switch (ext) {
    case 'jpeg':
    case 'jpg':
      return 'jpeg' // 统一返回 'jpeg'
    case 'png':
      return 'png'
    case 'webp':
      return 'webp'
    case 'bmp':
      return 'bmp'
    // 对于未知格式，默认返回 'png'
    default:
      return 'png'
  }
}

const loading = ref(false)

/**
 * 图片文件上传
 * @param file
 */
const handleUpload = async ({ file }: any) => {
  loading.value = true
  if (!loginUser) {
    message.error('请先登录')
    loading.value = false
    return
  }
  // 改为后端协同编辑统一校验
  // if (loginUser?.id !== props.picture?.userId) {
  //   message.error('无权裁切图片')
  //   loading.value = false
  //   return
  // }
  try {
    const params: API.PictureUploadRequest = props.picture ? { id: props.picture.id } : {}
    params.spaceId = props.spaceId
    const res = await uploadPictureByFileUsingPost(params, {}, file)
    // @ts-ignore
    if (res.data.code === 0 && res.data.data) {
      message.success('图片裁切成功')
      // @ts-ignore
      props.onSuccess?.(res.data.data)
      // @ts-ignore
      closeModal()
    } else {
      // @ts-ignore
      message.error('图片裁切失败，' + res.data.message)
    }
  } catch (error) {
    // @ts-ignore
    message.error('图片裁切失败，' + error.message)
  }
  loading.value = false
}

// 分享弹窗是否可见
const visible = ref<boolean>(false)

/**
 * 打开弹窗
 */
const openModal = () => {
  visible.value = true
}
/**
 * 关闭弹窗，如果有连接资源，需要释放连接
 * @param e
 */
const closeModal = (e: MouseEvent) => {
  visible.value = false
  // 断开 WebSocket 连接
  if (webSocket) {
    webSocket.disconnect()
  }
  editingUser.value = undefined
}

/**
 * 暴露函数给父组件
 */
defineExpose({
  openModal,
})

/**
 * 协同编辑
 */
// 正在编辑的成员
const editingUser = ref<API.MaskedUserVO>()
// 当前用户（不一定是成员）是否可进入编辑
const canEnterEdit = computed(() => {
  return !editingUser.value
})
// 正在编辑的用户是本人，可退出编辑
const canExitEdit = computed(() => {
  return editingUser.value?.id === loginUser.id
})
// 可以点击编辑图片的操作按钮
const canEdit = computed(() => {
  // 不是团队空间，无需判断，直接通过
  if (!isTeamSpace.value) {
    return true
  }
  return editingUser.value?.id === loginUser.id
})

// 编写 WebSocket 逻辑
let webSocket: PictureEditWebSocket | null
// 初始化 WebSocket 连接，绑定监听事件
const initWebSocket = () => {
  const pictureId = props.picture?.id
  // 没有图片或者裁剪图片弹窗未打开，不需要建立连接
  if (!pictureId || !visible.value) {
    return
  }
  // 防止之前的连接未释放，保险起见，再释放依次
  if (webSocket) {
    webSocket.disconnect()
  }
  // 创建 WebSocket 实例
  webSocket = new PictureEditWebSocket(pictureId)
  // 建立连接
  webSocket.connect()
  // 进入弹窗，如果有成员正在编辑，也要展示
  // webSocket.on('open', (msg) => {
  //   console.log('连接成功：', msg)
  //   if (msg.user) {
  //     editingUser.value = msg.user
  //     message.info(msg.message, 5)
  //   }
  // })
  // 监听一系列事件
  webSocket.on(PICTURE_EDIT_MESSAGE_TYPE_ENUM.INFO, (msg) => {
    console.log('收到通知消息：', msg)
    message.info(msg.message, 5)
  })
  webSocket.on(PICTURE_EDIT_MESSAGE_TYPE_ENUM.ERROR, (msg) => {
    console.log('收到错误通知：', msg)
    message.info(msg.message, 5)
  })
  webSocket.on(PICTURE_EDIT_MESSAGE_TYPE_ENUM.ENTER_EDIT, (msg) => {
    console.log('收到进入编辑状态消息：', msg)
    message.info(msg.message, 8)
    editingUser.value = msg.user
  })
  webSocket.on(PICTURE_EDIT_MESSAGE_TYPE_ENUM.EDIT_ACTION, (msg) => {
    console.log('收到编辑操作消息：', msg)
    message.info(msg.message)
    // 根据收到的编辑操作，执行相应的操作
    switch (msg.editAction) {
      case PICTURE_EDIT_ACTION_ENUM.ROTATE_LEFT:
        rotateLeft()
        break
      case PICTURE_EDIT_ACTION_ENUM.ROTATE_RIGHT:
        rotateRight()
        break
      case PICTURE_EDIT_ACTION_ENUM.ZOOM_IN:
        changeScale(1)
        break
      case PICTURE_EDIT_ACTION_ENUM.ZOOM_OUT:
        changeScale(-1)
        break
    }
  })
  webSocket.on(PICTURE_EDIT_MESSAGE_TYPE_ENUM.EXIT_EDIT, (msg) => {
    console.log('收到退出编辑状态消息：', msg)
    message.info(msg.message, 8)
    editingUser.value = undefined
  })
}

// 监听属性 和 visible 的变化，初始化 WebSocket 连接
watchEffect(() => {
  // 只有团队空间，才需要初始化 WebSocket 连接
  if (isTeamSpace.value) {
    initWebSocket()
  }
})

// 组件销毁、页面关闭、浏览器关闭时，要释放连接
onUnmounted(() => {
  // 断开 WebSocket 连接
  if (webSocket) {
    webSocket.disconnect()
  }
  editingUser.value = undefined
})

/**
 * 发送进入编辑状态的请求
 */
const enterEdit = () => {
  if (webSocket) {
    // 发送进入编辑状态的请求
    webSocket.sendMessage({
      type: PICTURE_EDIT_MESSAGE_TYPE_ENUM.ENTER_EDIT,
    })
  }
}
/**
 * 发送退出编辑状态的请求
 */
const exitEdit = () => {
  if (webSocket) {
    webSocket.sendMessage({
      type: PICTURE_EDIT_MESSAGE_TYPE_ENUM.EXIT_EDIT,
    })
  }
}
/**
 * 发送编辑操作请求
 */
const editAction = (action: string) => {
  if (webSocket) {
    webSocket.sendMessage({
      type: PICTURE_EDIT_MESSAGE_TYPE_ENUM.EDIT_ACTION,
      editAction: action,
    })
  }
}
</script>

<style>
.image-cropper {
  text-align: center;
}

.image-cropper .vue-cropper {
  height: 500px !important;
}

.full-modal {
  .ant-modal {
    max-width: 100%;
    top: 0;
    padding-bottom: 0;
    margin: 0;
  }
  .ant-modal-content {
    display: flex;
    flex-direction: column;
    height: calc(100vh);
  }
  .ant-modal-body {
    flex: 1;
  }
}
</style>
